home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_13_01 / kuzdrall / flttxf.c < prev    next >
Text File  |  1994-12-06  |  6KB  |  176 lines

  1.  
  2. /* ***< FLTTXF.CEE   >****/
  3. /* Copyright 1994 James A. Kuzdrall
  4.    Free license to this software is granted only if the above
  5.    copyright credit is included in the source code */
  6.  
  7.     #include  <stdio.h>          /* ANSI C definitions */
  8.     #define XFER_ERROR -1        /* a non-zero integer */
  9.     
  10.     static float  pwr2[9]= {
  11.       1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0 };
  12.     
  13.     /***< fputf     >*** ++++++++++++++++++++++++++++++++++++++++++++++ *
  14.     
  15.       USE....... Convert host's float to a 4-byte, IEEE-754, MSB-first
  16.         standard transfer format.  Send the 4 bytes to output stream fp.
  17.       RETURNS... Non-zero if error; otherwise, 0
  18.         No number sent if error.
  19.       ERRORS.... Disk errors of putc().
  20.         Out-of-range for absolute values beyond IEEE 4-byte float range,
  21.         about 3.402822e+38 to 1.175493e-38.
  22.     */
  23.     
  24.     int  fputf(np,fp)
  25.       float   *np;   /* number to be sent */
  26.       FILE    *fp;   /* stream (file) pointer */
  27.       {
  28.       float nr;      /* local copy of number */
  29.       char  iszero;  /* flag: 1 if nr is 0.0, else 0 */
  30.       int   expo;    /* build exponent here */
  31.       int   ix;      /* index for powers of two */
  32.       long  mant;    /* mantissa */
  33.       unsigned int  byt[4];   /* build IEEE float here */
  34.       int   err;
  35.     
  36.       byt[0]= iszero= 0;       /* preset float sign + and not zero */
  37.       expo= 127;               /* preset exponent bias at 2^0 */
  38.       if( (nr= *np) == 0.0 ) { /* zero won't scale; just send it */
  39.         iszero= 1;
  40.         goto pfout;            /* note: preset expo passes pfout test */
  41.         }
  42.     
  43.       /* get magnitude; put sign bit output byte */
  44.       if( nr < 0.0 ) {
  45.         byt[0]= 0x80;
  46.         nr= -nr;
  47.         }
  48.       
  49.       /* scale nr to 2^0 to 2^1 range; build exponent by powers of 2 */
  50.       while( nr < 1.0  &&  expo > 0 ) {    /* make small numbers > 1.0 */
  51.         nr *= 256.0;
  52.         expo -= 8;
  53.         }
  54.       for( ix= 8; --ix; ) {
  55.         while( nr >= pwr2[ix]  &&  expo < 255 ) {
  56.           nr /= pwr2[ix];
  57.           expo += ix;
  58.           }
  59.         }
  60.     
  61.       /* scale nr to 2^24 to 2^23 range; convert to long integer */
  62.       mant= (long )( nr * 8388608.0 );     /* 2^23 */
  63.       /* get mantissa bytes from the long */
  64.       byt[3]= mant;
  65.       byt[2]= (mant >> 8);
  66.       byt[1]= (mant >> 16);
  67.     
  68.       /* encode exponent */
  69.       if( expo & 0x0001 )         /* put lsb of expo in implied bit */
  70.         byt[1] |= 0x80;
  71.       else
  72.         byt[1] &= 0x7f;
  73.       /* combine rest of exponent and sign */
  74.       byt[0] |= (unsigned int )expo >> 1;
  75.     
  76.       pfout:
  77.       err= XFER_ERROR;                 /* preset */
  78.       /* look for out-of-range exponent and write errors */
  79.       if( expo < 255  &&  expo > 0 ) {
  80.         for( ix= 0; ix < 4; ix++ )
  81.           if( putc( (iszero ? 0 : (byt[ix] & 0xff)),fp) == EOF )
  82.             goto pfxit;
  83.         err= 0;
  84.         }
  85.       pfxit:
  86.       return( err );
  87.       }
  88.     
  89.     
  90.     /***< fgetf     >*** ++++++++++++++++++++++++++++++++++++++++++++++ *
  91.     
  92.       USE....... Read a standard transfer format, 4-byte, IEEE-754, MSB-
  93.         first float from the stream fp and convert it to the host's
  94.         float format.
  95.       RETURNS...  Non-zero if error; otherwise, 0
  96.         Places answer at pointer if no errors.
  97.       ERRORS.... From getc().
  98.         Bad exponent byte (255).
  99.     */
  100.     
  101.     
  102.     int  fgetf(np,fp)
  103.       float *np;       /* place where answer goes */
  104.       FILE  *fp;       /* stream (file) pointer */
  105.       {
  106.       int   ix;        /* byte counter */
  107.       char  nonzero;   /* true if any bits set */
  108.       int   expo;      /* exponent of IEEE float */
  109.       long  mant;      /* fractional part */
  110.       float pwr;       /* scale factor from exponent */
  111.       float ftemp;
  112.       unsigned int  byt[4];    /* transferred bytes, byt[0] is MSB */
  113.       int   err;
  114.     
  115.       /* read bytes from disk; check error */
  116.       err= XFER_ERROR;                 /* preset true */
  117.       nonzero= 0;                      /* preset false */
  118.       for( ix= 0; ix<4; ix++ ) {       /* byte read from MSB to LSB */
  119.         if( (byt[ix]= getc(fp)) == EOF )
  120.           goto gfxit;                  /* disk error, quit */
  121.         byt[ix] &= 0xff;               /* strip parity etc, if present */
  122.         if( byt[ix] )                  /* see if any bits set */
  123.           nonzero++;
  124.         }
  125.     
  126.       /* divide IEEE-754 float into parts */
  127.       expo= ((byt[0] << 1) | (byt[1] >> 7)) & 0xff;
  128.       mant= ( ( (long )(byt[1] | 0x80) << 16)  /* implied bit */
  129.             + (byt[2] << 8) + byt[3] );
  130.     
  131.       /* intercept IEEE-754 Inf, Nan, denormalized or just bad byte */
  132.       if( expo == 0xff  ||  (!expo  &&  nonzero) )
  133.         goto gfxit;
  134.     
  135.       /* special case: number is zero */
  136.       if( !nonzero ) {
  137.         *np= 0.0;
  138.         err= 0;
  139.         goto gfxit;
  140.         }
  141.     
  142.       /* build float value of exponent in pwr */
  143.       pwr= 1.0;       /* 2^0 scaling multiplier corresponds to expo=127 */
  144.       if( expo > 127 ) {
  145.         while( expo > 135 ) {
  146.           pwr *= 256.0;
  147.           expo -= 8;
  148.           }
  149.         pwr *= pwr2[expo-127];
  150.         }
  151.       else {
  152.         while( expo < 119 ) {
  153.           pwr *= .00390625;               /* equiv /= 256.0 */
  154.           expo += 8;
  155.           }
  156.         pwr /= pwr2[127-expo];
  157.         }
  158.     
  159.       /* check for over and under flow */
  160.       if( pwr > 0.0 ) {
  161.         if( byt[0] & 0x80 )
  162.           pwr= -pwr;                    /* set right sign */
  163.         /* convert mantissa to 1.0 to 2.0 range then scale by pwr */
  164.         ftemp= (float )mant/8388608.0;       /* mant/2^23 */
  165.         *np= ftemp * pwr;  /* separate lines prevent mant*pwr overflow */
  166.         err= 0;
  167.         }
  168.       gfxit:
  169.       return( err );
  170.       }
  171.  
  172.  
  173.  
  174.  
  175.  
  176.